/*
 * contiki_main.c
 *
 *  Created on: 2018-3-13
 *      Author: Iron
 */
#include "mem.h"
#include "osapi.h"
#include "user_interface.h"
#include "contiki.h"
#include "contiki-net.h"
#include "net/ip/uip.h"
#include "net/ip/dhcpc.h"

/*---------------------------------------------------------------------------*/
#define SLIP_ENABLE	 0
#define IS_GATEWAY	 0

/*----------------------------------------------------------------------------*/
#define CONTIKI_TASK_PRIO			USER_TASK_PRIO_0
#define CONTIKI_EVENT_NUM 			5

#define	CONTIKI_CLOCK_EVENT			0
#define	CONTIKI_RADIO_RX_EVENT		1
#define	CONTIKI_RADIO_TX_EVENT		2

static os_event_t *contiki_event_queue;

/*---------------------------------------------------------------------------*/
static int led_count = 0;
static uint8_t led_state = 0;

/*---------------------------------------------------------------------------*/
unsigned short node_id = 0x0102;

/*---------------------------------------------------------------------------*/
void led_set_state(int led_state);
void contiki_app_start(int gateway);

/*---------------------------------------------------------------------------*/
void ICACHE_FLASH_ATTR
contiki_main_clock_isr_cb(clock_time_t ticks)
{
	system_os_post(CONTIKI_TASK_PRIO, CONTIKI_CLOCK_EVENT, ticks);
}

void ICACHE_FLASH_ATTR
contiki_radio_tx_cb(void)
{
//	system_os_post(CONTIKI_TASK_PRIO, CONTIKI_RADIO_TX_EVENT, ticks);
}

void ICACHE_FLASH_ATTR
contiki_radio_rx_cb(void)
{
	system_os_post(CONTIKI_TASK_PRIO, CONTIKI_RADIO_RX_EVENT, 0);
}

/*---------------------------------------------------------------------------*/
#if UIP_CONF_LOGGING == 1
void uip_log(char *msg)
{
	os_printf("%d %s", clock_time(), msg);
}
#endif

/*---------------------------------------------------------------------------*/
static void ICACHE_FLASH_ATTR
set_rime_addr(void)
{
	int i;
	linkaddr_t addr;

	os_memset(&addr, 0x00, sizeof(linkaddr_t));

//	node_id = os_random();
	addr.u8[0] = node_id & 0xFF;
	addr.u8[1] = (node_id >> 8) & 0xFF;

#if !IS_GATEWAY
	{
		uint8_t softap_mac[6];
		wifi_get_macaddr(SOFTAP_IF, softap_mac);

#if	LINKADDR_CONF_SIZE == 8
		os_memcpy(&addr.u8[2], softap_mac, 6);
#else
		addr.u8[0] = softap_mac[4];
		addr.u8[1] = softap_mac[5];
#endif
	}
#endif

	linkaddr_set_node_addr(&addr);

	os_printf("Rime started with address: ");
	for(i = 0; i < LINKADDR_SIZE - 1; i++) {
		os_printf("%02x.", addr.u8[i]);
	}
	os_printf("%02x\n", addr.u8[LINKADDR_SIZE - 1]);
}

/*---------------------------------------------------------------------------*/
#if NETSTACK_CONF_WITH_IPV4
#include "dev/slip.h"
#include "net/ip/uip.h"
#include "net/ipv4/uip-fw.h"
#include "net/ipv4/uip-fw-drv.h"
#include "net/ipv4/uip-over-mesh.h"

#if SLIP_ENABLE
static struct uip_fw_netif slipif =
	{ UIP_FW_NETIF(192, 168, 1, 2, 255, 255, 255, 255, slip_send) };
#endif

static struct uip_fw_netif meshif =
	{ UIP_FW_NETIF(172, 16, 0, 0, 255, 255, 0, 0, uip_over_mesh_send) };

#define UIP_OVER_MESH_CHANNEL 	8


#if SLIP_ENABLE
static void ICACHE_FLASH_ATTR
set_gateway(void)
{
	static uint8_t is_gateway = 0;

	if(!is_gateway) {
//      leds_on(LEDS_RED);
		os_printf("%d.%d: making myself the IP network gateway.\n\n",
			   linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1]);
		os_printf("IPv4 address of the gateway: %d.%d.%d.%d\n\n",
			   uip_ipaddr_to_quad(&uip_hostaddr));
		uip_over_mesh_set_gateway(&linkaddr_node_addr);
		uip_over_mesh_make_announced_gateway();
		is_gateway = 1;
	}
}
#endif

#endif /* NETSTACK_CONF_WITH_IPV4 */

/*---------------------------------------------------------------------------*/
void ICACHE_FLASH_ATTR
contiki_init(void)
{
	/* Print startup information */
	os_printf("\n" CONTIKI_VERSION_STRING " started.\n");

	/* Initialize Contiki and our processes. */
	clock_init();
	ctimer_init();
	rtimer_init();

	/* start process handler */
	process_init();
	process_start(&etimer_process, NULL);

	/* Initialize communication stack */
	set_rime_addr();
	netstack_init();

	os_printf("%s/%s/%s, channel check rate %d Hz\n",
		 NETSTACK_NETWORK.name, NETSTACK_MAC.name, NETSTACK_RDC.name,
		 CLOCK_SECOND / (NETSTACK_RDC.channel_check_interval() == 0 ? 1 : NETSTACK_RDC.channel_check_interval()));

	/* IPv4 CONFIGURATION */
#if NETSTACK_CONF_WITH_IPV4
	{
		uip_ipaddr_t hostaddr, netmask;

		process_start(&tcpip_process, NULL);
		process_start(&uip_fw_process, NULL);

		uip_init();
		uip_fw_init();

#if IS_GATEWAY || LINKADDR_SIZE == 2
		uip_ipaddr(&hostaddr, 172, 16, linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1]);
#else
		uip_ipaddr(&hostaddr, 172, 16, linkaddr_node_addr.u8[6], linkaddr_node_addr.u8[7]);
#endif
		uip_ipaddr(&netmask, 255, 255, 0, 0);
		uip_ipaddr_copy(&meshif.ipaddr, &hostaddr);

		uip_sethostaddr(&hostaddr);
		uip_setnetmask(&netmask);

		uip_over_mesh_set_net(&hostaddr, &netmask);
//		uip_over_mesh_set_gateway_netif(&slipif);
		uip_fw_default(&meshif);

		uip_over_mesh_init(UIP_OVER_MESH_CHANNEL);

		// slip gateway
#if SLIP_ENABLE
		process_start(&slip_process, NULL);
		slip_set_input_callback(set_gateway);
//		rs232_set_input(slip_input_byte);
#endif

#if IS_GATEWAY
		uip_over_mesh_make_announced_gateway();
#else
		{	// rime gateway addr
			linkaddr_t gateway_addr;
			os_memset(&gateway_addr, 0x00, sizeof(linkaddr_t));
			gateway_addr.u8[0] = node_id & 0xFF;
			gateway_addr.u8[1] = (node_id >> 8) & 0xFF;
			uip_over_mesh_set_gateway(&gateway_addr);
		}
#endif

		os_printf("uIP started with IP address %d.%d.%d.%d\n", uip_ipaddr_to_quad(&hostaddr));
	}
#endif

	/* start application processes */
	contiki_app_start(IS_GATEWAY);

	/* Start autostart processes (defined in Contiki application) */
#if AUTOSTART_ENABLE
	autostart_start(autostart_processes);
#endif
}

/*---------------------------------------------------------------------------*/
void ICACHE_FLASH_ATTR
contiki_main_task(os_event_t *e)
{
	switch(e->sig){
	case CONTIKI_CLOCK_EVENT:
		do {
			system_soft_wdt_feed();
		} while(process_run() > 0);

		// led blink
		led_count++;
		if(led_count > 10){
			led_count = 0;
			led_state = !led_state;
			led_set_state(led_state);
		}

//		os_printf("clock event: %d/%d\n", e->par, clock_time());
		break;

	case CONTIKI_RADIO_RX_EVENT:
		{
			int len = 0;

//			os_printf("radio rx event\n");

			do{
				system_soft_wdt_feed();
				packetbuf_clear();
				len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
				if(len > 0) {
					packetbuf_set_datalen(len);
					NETSTACK_RDC.input();
				}
			}while(len > 0);
		}
		break;
	}
}

/*---------------------------------------------------------------------------*/
void ICACHE_FLASH_ATTR
contiki_start(void)
{
	contiki_init();

	contiki_event_queue = (os_event_t *)os_malloc(sizeof(os_event_t) * CONTIKI_EVENT_NUM);
	system_os_task(contiki_main_task, CONTIKI_TASK_PRIO, contiki_event_queue, CONTIKI_EVENT_NUM);
}
